Jx.categorize('lang.css.selector.tokenizer', {

	$extend: 'Jx.code.Tokenizer',

	states: {

		'start': {
			'"': 'str1',
			'[': 'openattr',
			']': 'closeattr',
			'(': 'openparenthesis',
			')': 'closeparenthesis',
			'#': 'idattr',
			'.': 'classattr',
			',': 'groupdelimiter',
			' ': 'whitespace',
			'\t': 'whitespace',
			'\r': 'whitespace',
			'\n': 'whitespace',
			'[*]': 'excess',

			':': 'selector',

			'=': 'op_eq',
			'~': 'op_ws_eq1',
			'^': 'op_begin_eq1',
			'$': 'op_end_eq1',
			'*': 'op_substr_eq1',
			'|': 'op_hyphen_eq1',
			'!': 'op_not_eq1',

			'>': 'child_of',

			'+': 'sibling_preceded'

		},

		'op_eq': {},
		'op_ws_eq2': {},
		'op_begin_eq2': {},
		'op_end_eq2': {},
		'op_substr_eq2': {},
		'op_hyphen_eq2': {},

		'op_not_eq1': {
			'=': 'op_not_eq2'
		},

		'op_ws_eq1': {
			'=': 'op_ws_eq2'
		},
		'op_begin_eq1': {
			'=': 'op_begin_eq2'
		},
		'op_end_eq1': {
			'=': 'op_end_eq2'
		},
		'op_substr_eq1': {
			'=': 'op_substr_eq2'
		},
		'op_hyphen_eq1': {
			'=': 'op_hyphen_eq2'
		},

		'whitespace': {

			' ': 'whitespace',
			'\t': 'whitespace',
			'\r': 'whitespace',
			'\n': 'whitespace',

			'+': 'combinator_immediate_preceded1',
			'>': 'combinator_child1',
			'~': 'combinator_preceded1',

			',': 'groupdelimiter'

		},

		'groupdelimiter': {

			' ': 'groupdelimiter',
			'\t': 'groupdelimiter',
			'\r': 'groupdelimiter',
			'\n': 'groupdelimiter'

		},

		'combinator_immediate_preceded1': {
			' ': 'combinator_immediate_preceded1',
			'\t': 'combinator_immediate_preceded1',
			'\r': 'combinator_immediate_preceded1',
			'\n': 'combinator_immediate_preceded1'
		},

		'combinator_child1': {
			' ': 'combinator_child1',
			'\t': 'combinator_child1',
			'\r': 'combinator_child1',
			'\n': 'combinator_child1'
		},
		'combinator_preceded1': {
			' ': 'combinator_preceded1',
			'\t': 'combinator_preceded1',
			'\r': 'combinator_preceded1',
			'\n': 'combinator_preceded1'
		},

		'namesuffix': {

			'[*]': 'namesuffix'

		},

		'str1': {
			'[*]': 'str1',
			'\\': 'esc1',
			'"': 'str2'
		},

		'esc1': {
			'0': 'eschex1',
			'1': 'eschex1',
			'2': 'eschex1',
			'3': 'eschex1',
			'4': 'eschex1',
			'5': 'eschex1',
			'6': 'eschex1',
			'7': 'eschex1',
			'8': 'eschex1',
			'9': 'eschex1',
			'a': 'eschex1',
			'b': 'eschex1',
			'c': 'eschex1',
			'd': 'eschex1',
			'e': 'eschex1',
			'f': 'eschex1',
			'A': 'eschex1',
			'B': 'eschex1',
			'C': 'eschex1',
			'D': 'eschex1',
			'E': 'eschex1',
			'F': 'eschex1',
			'[*]': 'str1'
		},

		'eschex1': {
			'0': 'eschex2',
			'1': 'eschex2',
			'2': 'eschex2',
			'3': 'eschex2',
			'4': 'eschex2',
			'5': 'eschex2',
			'6': 'eschex2',
			'7': 'eschex2',
			'8': 'eschex2',
			'9': 'eschex2',
			'a': 'eschex2',
			'b': 'eschex2',
			'c': 'eschex2',
			'd': 'eschex2',
			'e': 'eschex2',
			'f': 'eschex2',
			'A': 'eschex2',
			'B': 'eschex2',
			'C': 'eschex2',
			'D': 'eschex2',
			'E': 'eschex2',
			'F': 'eschex2',
			'[*]': 'eschexbefore'
		},

		'eschex2': {
			'0': 'eschex3',
			'1': 'eschex3',
			'2': 'eschex3',
			'3': 'eschex3',
			'4': 'eschex3',
			'5': 'eschex3',
			'6': 'eschex3',
			'7': 'eschex3',
			'8': 'eschex3',
			'9': 'eschex3',
			'a': 'eschex3',
			'b': 'eschex3',
			'c': 'eschex3',
			'd': 'eschex3',
			'e': 'eschex3',
			'f': 'eschex3',
			'A': 'eschex3',
			'B': 'eschex3',
			'C': 'eschex3',
			'D': 'eschex3',
			'E': 'eschex3',
			'F': 'eschex3',
			'[*]': 'eschexbefore'
		},

		'eschex3': {
			'0': 'eschex4',
			'1': 'eschex4',
			'2': 'eschex4',
			'3': 'eschex4',
			'4': 'eschex4',
			'5': 'eschex4',
			'6': 'eschex4',
			'7': 'eschex4',
			'8': 'eschex4',
			'9': 'eschex4',
			'a': 'eschex4',
			'b': 'eschex4',
			'c': 'eschex4',
			'd': 'eschex4',
			'e': 'eschex4',
			'f': 'eschex4',
			'A': 'eschex4',
			'B': 'eschex4',
			'C': 'eschex4',
			'D': 'eschex4',
			'E': 'eschex4',
			'F': 'eschex4',
			'[*]': 'eschexbefore'
		},

		'eschex4': {
			'0': 'eschex5',
			'1': 'eschex5',
			'2': 'eschex5',
			'3': 'eschex5',
			'4': 'eschex5',
			'5': 'eschex5',
			'6': 'eschex5',
			'7': 'eschex5',
			'8': 'eschex5',
			'9': 'eschex5',
			'a': 'eschex5',
			'b': 'eschex5',
			'c': 'eschex5',
			'd': 'eschex5',
			'e': 'eschex5',
			'f': 'eschex5',
			'A': 'eschex5',
			'B': 'eschex5',
			'C': 'eschex5',
			'D': 'eschex5',
			'E': 'eschex5',
			'F': 'eschex5',
			'[*]': 'eschexbefore'
		},

		'eschex5': {
			'0': 'eschex',
			'1': 'eschex',
			'2': 'eschex',
			'3': 'eschex',
			'4': 'eschex',
			'5': 'eschex',
			'6': 'eschex',
			'7': 'eschex',
			'8': 'eschex',
			'9': 'eschex',
			'a': 'eschex',
			'b': 'eschex',
			'c': 'eschex',
			'd': 'eschex',
			'e': 'eschex',
			'f': 'eschex',
			'A': 'eschex',
			'B': 'eschex',
			'C': 'eschex',
			'D': 'eschex',
			'E': 'eschex',
			'F': 'eschex',
			'[*]': 'eschexbefore'
		},

		'eschex': {},
		'eschexbefore': {},

		'openattr' : {},
		'closeattr': {},

		'idattr': {},
		'classattr': {},

		'excess': {},
		'selector': {

			':': 'pseudo_selector'

		},

		'openparenthesis': {},
		'closeparenthesis': {},

		'child_of': {},

		'sibling_preceded': {},

		'pseudo_selector': {}



	},

	stateCallback: {


		//-- string
		'eschex1': function(chr, input, state, previousState){

			this.hexBuffer+=chr;

		},
		'eschex': function(chr, input, state, previousState){

			//this.appendBuffer(chr);
			this.hexBuffer+=chr;

			this.endHex.apply(this, arguments);

		},

		'eschexbefore': function(chr, input, state, previousState){

			this.backtrack(1);

			//-- replace
			this.endHex.apply(this, arguments);

		},

		'esc1': function(chr, input, state, previousState){

			//-- dont include '\' character

		},


		'str1': function(chr, input, state, previousState){

			if (previousState != 'start'){

				this.appendBuffer(chr);

			}

		},

		'str2': function(chr, input, state, previousState){

			return 'string';

		},

		//-- attribute operator
		'openattr': function(chr){

			this.appendBuffer(chr);

			return '[';

		},
		'closeattr': function(chr){

			this.appendBuffer(chr);

			return ']';

		},

		//-- id
		'idattr': function(chr){

			this.appendBuffer(chr);

			return '#';


		},

		//-- class
		'classattr': function(chr){

			this.appendBuffer(chr);

			return '.';

		},

		'excess': function(chr, input, state, previousState){

			var ret = this.nameStartRe.test(chr);

			//-- is name
			if (ret){

				this.state = 'namesuffix';

				this.appendBuffer(chr);

				ret = 'name';

			} else {

				ret = false;

				this.backtrack(1);

			}

			return ret;


		},

		'namesuffix': function(chr){

			var ret = this.nameSuffixRe.test(chr);

			if (ret){

				this.appendBuffer(chr);

				ret = 'name';

			} else {

				this.backtrack(1);

			}

			return ret;

		},

		'whitespace': function(chr){

			this.appendBuffer(chr);

			return 'whitespace';

		},
		'op_eq': function(chr){

			this.appendBuffer(chr);

			return '=';

		},

		'op_not_eq2': function(chr){

			this.appendBuffer(chr);

			return '!=';

		},

		'op_ws_eq2': function(chr){

			this.appendBuffer(chr);

			return '~=';

		},

		'op_begin_eq2': function(chr){

			this.appendBuffer(chr);

			return '^=';

		},
		'op_end_eq2': function(chr){

			this.appendBuffer(chr);

			return '$=';

		},

		'op_substr_eq1': function(chr){

			this.appendBuffer(chr);

			return '*';

		},

		'op_substr_eq2': function(chr){

			this.appendBuffer(chr);

			return '*=';

		},

		'op_hyphen_eq1': function(chr){

			this.appendBuffer(chr);

			return '|';

		},

		'op_hyphen_eq2': function(chr){

			this.appendBuffer(chr);

			return '|=';

		},
		'combinator_preceded1': function(chr){

			this.appendBuffer(chr);

			return '~';

		},
		'op_ws_eq1': function(chr){

			this.appendBuffer(chr);

			return '~';

		},

		'combinator_child1': function(chr){

			this.appendBuffer(chr);

			return '>';

		},

		'child_of': function(chr){

			this.appendBuffer(chr);

			return '>';

		},

		'combinator_immediate_preceded1': function(chr){

			this.appendBuffer(chr);

			return '+';

		},

		'sibling_preceded': function(chr){

			this.appendBuffer(chr);

			return '+';

		},

		'selector': function(chr){

			this.appendBuffer(chr);

			return ':';

		},

		'groupdelimiter': function(chr){

			this.appendBuffer(chr);

			return ',';

		},

		'pseudo_selector': function(chr){

			this.appendBuffer(chr);

			return '::';

		},



		'openparenthesis': function(chr){

			this.appendBuffer(chr);

			return '(';

		},
		'closeparenthesis': function(chr){

			this.appendBuffer(chr);

			return ')';

		}


	},

	nameStartRe: /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/,

	nameSuffixRe: /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-0-9\u00B7\u0300-\u036F\u203F-\u2040]/,

	hexBuffer: undefined,

	constructor: function(){

		this.hexBuffer = '';

		this.$super(arguments);

	},

	endHex: function(chr, input, state, previousState){

		this.appendBuffer(

			String.fromCharCode(

				parseInt(this.hexBuffer, 16)

			)

		);

		this.state = 'str1';

	}

});
